import { useMedia } from "@/hooks/useMedia";

export enum BindType {
  Path = "Path",
  Start = "Start",
  End = "End",
}

export enum EventStage {
  Start = "Start",
  Move = "Move",
  End = "End",
}

export const useMove = () => {
  function onMouseDown(
    e: Event,
    el: HTMLDivElement,
    callback: (
      params: Partial<{
        start: Event;
        end: Event;
        type: BindType;
        stage: EventStage;
      }>
    ) => void
  ) {
    const target = e.target as Element;
    const parent = target.parentNode as Element;
    const classList = Array.from(target?.classList || []).concat(
      Array.from(parent?.classList || [])
    );
    if (
      !classList.includes("_progress-circle") &&
      !classList.includes("_progress-end") &&
      !classList.includes("_progress-start")
    ) {
      return;
    }

    let type = BindType.Path;
    if (classList.includes("_progress-end")) {
      type = BindType.End;
    } else if (classList.includes("_progress-start")) {
      type = BindType.Start;
    }

    let start = e;
    function onExecuteCallback(e, stage: EventStage) {
      window.requestAnimationFrame(() => {
        callback?.({
          start,
          end: e,
          type,
          stage,
        });
        start = e;
      });
    }

    function onMouseMove(e) {
      onExecuteCallback(e, EventStage.Move);
    }

    function onRemoveListener(e) {
      el.removeEventListener("mousemove", onMouseMove);
      el.removeEventListener("mouseup", onRemoveListener);
      el.removeEventListener("mouseleave", onRemoveListener);
      onExecuteCallback(e, EventStage.End);
    }

    el.addEventListener("mousemove", onMouseMove, false);
    el.addEventListener("mouseup", onRemoveListener);
    el.addEventListener("mouseleave", onRemoveListener, false);
  }

  function onTouch(
    e: Event,
    el: HTMLDivElement,
    callback: (
      params: Partial<{
        start: Event;
        end: Event;
        type: BindType;
        stage: EventStage;
      }>
    ) => void
  ) {
    const target = e.target as Element;
    const parent = target.parentNode as Element;
    const classList = Array.from(target?.classList || []).concat(
      Array.from(parent?.classList || [])
    );
    if (
      !classList.includes("_progress-circle") &&
      !classList.includes("_progress-end") &&
      !classList.includes("_progress-start")
    ) {
      return;
    }

    let type = BindType.Path;
    if (classList.includes("_progress-end")) {
      type = BindType.End;
    } else if (classList.includes("_progress-start")) {
      type = BindType.Start;
    }

    let start = e;
    function onExecuteCallback(e, stage: EventStage) {
      window.requestAnimationFrame(() => {
        callback?.({
          start,
          end: e,
          type,
          stage,
        });
        start = e;
      });
    }

    function onToucMove(e) {
      e.preventDefault();
      onExecuteCallback(e, EventStage.Move);
    }

    function onRemoveListener(e) {
      e.preventDefault();
      el.removeEventListener("touchmove", onToucMove);
      el.removeEventListener("touchend", onRemoveListener);
      onExecuteCallback(e, EventStage.End);
    }

    el.addEventListener("touchmove", onToucMove, {
      passive: false,
    });
    el.addEventListener("touchend", onRemoveListener, {
      passive: false,
    });
  }

  const vMove = {
    mounted: (el: HTMLDivElement, binding) => {
      const isMobile = useMedia();
      !isMobile.value &&
        el.addEventListener(
          "mousedown",
          (e) => onMouseDown(e, el, binding.value),
          false
        );
      isMobile.value &&
        el.addEventListener(
          "touchstart",
          (e) => onTouch(e, el, binding.value),
          {
            passive: false,
          }
        );
    },
    beforeUnmount: (el: HTMLDivElement, binding) => {
      const isMobile = useMedia();
      !isMobile.value &&
        el.removeEventListener("mousedown", (e) =>
          onMouseDown(e, el, binding.value)
        );
      isMobile.value &&
        el.removeEventListener("touchstart", (e) =>
          onTouch(e, el, binding.value)
        );
    },
  };
  return { vMove };
};
